#ifndef __PREFERENCES_H__
#define __PREFERENCES_H__

#include <map>
#include <cstring>
#include <string>
#include <type_traits>
#include <cstdint>
#include <vector>
#include <memory>
#include <numeric>

class Preferences
{
private:
    typedef std::vector<uint8_t> data_element_t;      // 定义数据元素结构体
    std::map<data_element_t, data_element_t> __prefs; // 用于存储键值对

    /// @brief 将基本类型转换为data_element_t
    /// @tparam T 基本类型
    /// @param value 基本类型的值
    /// @return 转换后的data_element_t
    template <typename T,
              typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
    data_element_t __to_data_element(const T &value)
    {
        size_t length = sizeof(T);
        data_element_t element(length);
        std::copy(reinterpret_cast<const uint8_t *>(&value), reinterpret_cast<const uint8_t *>(&value) + length, element.begin());
        return element;
    }

    /// @brief 处理字符串类型的特化版本
    data_element_t __to_data_element(const char *value)
    {
        size_t length = std::strlen(value);
        data_element_t element(length + 1);
        std::copy(reinterpret_cast<const uint8_t *>(value), reinterpret_cast<const uint8_t *>(value) + length + 1, element.begin());
        return element;
    }

    /// @brief 处理字符串类型的特化版本
    data_element_t __to_data_element(const std::string &value)
    {
        return __to_data_element(value.c_str()); // 重用char*实现
    }

    /// @brief 处理数组类型
    /// @tparam T 数组元素类型
    /// @param value 数组指针
    /// @param value_size 数组大小
    /// @return 转换后的data_element_t
    template <typename T>
    data_element_t __to_data_element(T *value, size_t value_size)
    {
        size_t length = value_size * sizeof(T);
        data_element_t element(length);
        std::copy(reinterpret_cast<const uint8_t *>(value), reinterpret_cast<const uint8_t *>(value) + length, element.begin());
        return element;
    }

    /// @brief 将data_element_t转换为基本类型
    /// @tparam T 基本类型
    /// @param element data_element_t对象
    /// @return 转换后的基本类型值
    template <typename T,
              typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
    T __from_data_element(const data_element_t &element)
    {
        T value;
        std::copy(element.begin(), element.end(), reinterpret_cast<uint8_t *>(&value));
        return value;
    }

    /// @brief 处理字符串类型的特化版本
    /// @param element data_element_t对象
    std::string __from_data_element_string(const data_element_t &element)
    {
        return std::string(reinterpret_cast<const char *>(element.data()));
    }

    /// @brief 处理数组的专门函数
    /// @param element data_element_t对象
    /// @param out_array 输出数组指针
    /// @param out_size 输出数组大小
    template <typename T>
    void __from_data_element_array(const data_element_t &element, T **out_array, size_t *out_size)
    {
        *out_size = element.size() / sizeof(T);
        *out_array = new T[*out_size];                         // 动态分配内存
        std::copy(element.begin(), element.end(), *out_array); // 复制数组数据
    }

public:
    Preferences() {}

    virtual ~Preferences() {}

    /// @brief 获取序列化后的数据大小
    /// @return 返回序列化后的数据大小
    inline size_t serialize_size() const
    {
        size_t total_size = sizeof(size_t); // 为map的大小保留空间
        for (const auto &pair : __prefs)
        {
            total_size += sizeof(size_t) + pair.first.size() +
                          sizeof(size_t) + pair.second.size(); // 压缩键和值的大小
        }
        return total_size;
    }

    /// @brief 将当前数据序列化为二进制数据
    /// @param buffer 输出缓冲区指针
    /// @param size 输出缓冲区大小
    /// @return 校验和
    uint8_t serialize(uint8_t **buffer, size_t *size)
    {
        size_t total_size{serialize_size()};
        uint8_t *ptr = *buffer;

        const char identifier[] = "NLZP";
        size_t identifier_size = sizeof(identifier) - 1;

        // 写入标识符
        std::memcpy(ptr, identifier, identifier_size);
        ptr += identifier_size;

        // 写入map的大小
        size_t prefs_size = __prefs.size();
        std::memcpy(ptr, &prefs_size, sizeof(size_t));
        ptr += sizeof(size_t);

        // 用于计算校验和
        uint8_t checksum = 0;

        for (const auto &pair : __prefs)
        {
            size_t key_size = pair.first.size();
            std::memcpy(ptr, &key_size, sizeof(size_t));
            ptr += sizeof(size_t);
            std::memcpy(ptr, pair.first.data(), key_size);
            ptr += key_size;

            size_t value_size = pair.second.size();
            std::memcpy(ptr, &value_size, sizeof(size_t));
            ptr += sizeof(size_t);
            std::memcpy(ptr, pair.second.data(), value_size);
            ptr += value_size;

            // 计算校验和
            checksum ^= key_size;
            checksum ^= value_size;
            checksum ^= std::accumulate(pair.first.begin(), pair.first.end(), 0);
            checksum ^= std::accumulate(pair.second.begin(), pair.second.end(), 0);
        }

        // 写入校验和
        std::memcpy(ptr, &checksum, sizeof(checksum));
        ptr += sizeof(checksum);

        *size = total_size + identifier_size + sizeof(checksum);

        return checksum;
    }

    /// @brief 从二进制数据加载数据
    /// @param buffer 输入缓冲区指针
    /// @param max_size 输入缓冲区最大大小
    /// @return 加载成功返回true，否则返回false
    /// @warning 需要保证buffer的大小足够容纳序列化数据，否则可能导致未定义行为
    bool deserialize(const uint8_t *buffer, size_t max_size = 1024)
    {
        // 检查标识符
        const char identifier[] = "NLZP";
        size_t identifier_size = sizeof(identifier) - 1;

        // 检查缓冲区大小是否足够
        if (max_size < identifier_size + sizeof(size_t))
        {
            return false; // 缓冲区太小
        }

        // 检查标识符
        if (std::memcmp(buffer, identifier, identifier_size) != 0)
        {
            return false; // 标识符不匹配
        }

        const uint8_t *ptr = buffer + identifier_size;
        size_t map_size;
        std::memcpy(&map_size, ptr, sizeof(size_t));
        ptr += sizeof(size_t);

        // 检查 map_size 是否合理以及剩余的缓冲区是否足够
        if (ptr - buffer + sizeof(size_t) + map_size * (sizeof(size_t) + sizeof(size_t)) > max_size)
        {
            return false; // 数据长度超出限制
        }

        uint8_t checksum = 0;
        uint8_t calculated_checksum = 0;

        for (size_t i = 0; i < map_size; ++i)
        {
            size_t key_size;
            std::memcpy(&key_size, ptr, sizeof(size_t));
            ptr += sizeof(size_t);

            // 检查键的大小是否合理
            if (ptr - buffer + key_size + sizeof(size_t) + sizeof(size_t) > max_size)
            {
                return false; // 数据长度超出限制
            }

            data_element_t key(key_size);
            std::copy(ptr, ptr + key_size, key.begin());
            ptr += key_size;

            size_t value_size;
            std::memcpy(&value_size, ptr, sizeof(size_t));
            ptr += sizeof(size_t);

            // 检查值的大小是否合理
            if (ptr - buffer + value_size > max_size)
            {
                return false; // 数据长度超出限制
            }

            data_element_t value(value_size);
            std::copy(ptr, ptr + value_size, value.begin());
            ptr += value_size;

            // 校验和计算
            calculated_checksum ^= key_size;
            calculated_checksum ^= value_size;
            calculated_checksum ^= std::accumulate(key.begin(), key.end(), 0);
            calculated_checksum ^= std::accumulate(value.begin(), value.end(), 0);

            __prefs[key] = value; // 存储键值对
        }

        // 读取校验和
        if (ptr - buffer + sizeof(checksum) > max_size)
        {
            return false; // 数据长度超出限制
        }
        std::memcpy(&checksum, ptr, sizeof(checksum));

        // 比较校验和
        if (checksum != calculated_checksum)
        {
            return false; // 校验和不匹配，表示数据错误
        }

        return true;
    }

    /// @brief 设置指定键的值（普通类型）
    /// @tparam KEY_T 键类型
    /// @tparam VALUE_T 值类型
    /// @param key 键
    /// @param value 值
    template <typename KEY_T, typename VALUE_T>
    void set(KEY_T &&key, VALUE_T &&value)
    {
        // 将键转换为data_element_t
        data_element_t keyElement = __to_data_element(std::forward<KEY_T>(key));
        data_element_t valueElement = __to_data_element(std::forward<VALUE_T>(value));

        // 更新map中的值
        __prefs[keyElement] = valueElement;
    }

    /// @brief 设置指定键的值（数组类型）
    /// @tparam KEY_T 键类型
    /// @tparam VALUE_T 值类型
    /// @param key 键
    /// @param value 值
    /// @param value_size 值的大小
    template <typename KEY_T, typename VALUE_T>
    void set(KEY_T &&key, VALUE_T *value, size_t value_size)
    {
        // 将键转换为data_element_t
        data_element_t keyElement = __to_data_element(std::forward<KEY_T>(key));
        data_element_t valueElement = __to_data_element(value, value_size);

        // 更新map中的值
        __prefs[keyElement] = valueElement;
    }

    /// @brief 设置指定键的值（std::vector类型）
    /// @tparam KEY_T 键类型
    /// @tparam VALUE_T 值类型
    /// @param key 键
    /// @param value 值
    /// @param value_size 值的大小
    template <typename KEY_T, typename VALUE_T>
    void set(KEY_T &&key, const std::vector<VALUE_T> &value)
    {
        // 将键转换为data_element_t
        data_element_t keyElement = __to_data_element(std::forward<KEY_T>(key));
        data_element_t valueElement = __to_data_element(value.data(), value.size());

        // 更新map中的值
        __prefs[keyElement] = valueElement;
    }

    /// @brief 设置指定键的值（std::shared_ptr类型）
    /// @tparam KEY_T 键类型
    /// @tparam VALUE_T 值类型
    /// @param key 键
    /// @param value 值
    template <typename KEY_T, typename VALUE_T>
    void set(KEY_T &&key, std::shared_ptr<VALUE_T> value)
    {
        // 将键转换为data_element_t
        data_element_t keyElement = __to_data_element(std::forward<KEY_T>(key));
        data_element_t valueElement = __to_data_element(value.get(), value->size());

        // 更新map中的值
        __prefs[keyElement] = valueElement;
    }

    /// @brief 获取指定键的值（std::string）
    /// @tparam KEY_T 键类型
    /// @param key 键
    /// @param default_value 默认值
    /// @return 值或默认值
    template <typename KEY_T>
    std::string get(KEY_T &&key, const std::string &default_value)
    {
        auto it = __prefs.find(__to_data_element(std::forward<KEY_T>(key)));
        if (it != __prefs.end())
        {
            return __from_data_element_string(it->second); // 对std::string的特殊处理
        }
        return default_value;
    }

    /// @brief 获取指定键的值（普通类型）
    /// @tparam KEY_T 键类型
    /// @tparam VALUE_T 值类型
    /// @param key 键
    /// @param default_value 默认值
    /// @return 值或默认值
    template <typename KEY_T, typename VALUE_T>
    std::decay_t<VALUE_T> get(KEY_T &&key, VALUE_T &&default_value)
    {
        auto it = __prefs.find(__to_data_element(std::forward<KEY_T>(key)));
        if (it != __prefs.end())
        {
            return __from_data_element<std::decay_t<VALUE_T>>(it->second);
        }
        return default_value;
    }

    /// @brief 获取指定键的值（数组类型）
    /// @tparam KEY_T 键类型
    /// @tparam VALUE_T 值类型
    /// @param key 键
    /// @param out_array 输出数组指针
    /// @param out_size 输出数组大小
    /// @note out_array为数组指针或nullptr
    /// @note out_array如果不为nullptr，则需要手动释放内存
    template <typename KEY_T, typename VALUE_T>
    void get(KEY_T &&key, VALUE_T **out_array, size_t *out_size)
    {
        auto it = __prefs.find(__to_data_element(std::forward<KEY_T>(key)));
        if (it != __prefs.end())
        {
            __from_data_element_array(it->second, out_array, out_size); // 从data_element_t中提取数组
            return;
        }

        *out_array = nullptr;
        *out_size = 0; // 如果未找到，则设置大小为0
    }

    /// @brief 获取指定键的值（std::vector）
    /// @tparam KEY_T 键类型
    /// @tparam VALUE_T 值类型
    /// @param key 键
    /// @param default_array 默认数组
    /// @return 返回std::vector对象
    /// @note out_array为std::vector对象
    template <typename KEY_T, typename VALUE_T>
    std::vector<VALUE_T> get(KEY_T &&key, std::vector<VALUE_T> default_array)
    {
        auto it = __prefs.find(__to_data_element(std::forward<KEY_T>(key)));
        if (it == __prefs.end())
        {
            return default_array; // 返回std::vector的引用
        }

        std::vector<VALUE_T> out_array(it->second.size() / sizeof(VALUE_T));
        std::copy(it->second.begin(), it->second.end(), out_array.begin());
        return out_array;
    }

    /// @brief 获取指定键的值（std::shared_ptr）
    /// @tparam KEY_T 键类型
    /// @tparam VALUE_T 值类型
    /// @param key 键
    /// @param default_array 默认数组
    /// @return 返回std::shared_ptr对象
    /// @note out_array为std::shared_ptr对象
    template <typename KEY_T, typename VALUE_T>
    std::shared_ptr<VALUE_T> get(KEY_T &&key, std::shared_ptr<VALUE_T> default_array)
    {
        auto it = __prefs.find(__to_data_element(std::forward<KEY_T>(key)));
        if (it == __prefs.end())
        {
            return default_array; // 返回std::vector的引用
        }

        std::shared_ptr<VALUE_T> out_array = std::make_shared<VALUE_T>(it->second.size() / sizeof(VALUE_T));
        std::copy(it->second.begin(), it->second.end(), out_array.get());
        return out_array;
    }

    /// @brief 删除指定键的值
    /// @tparam KEY_T 键类型
    /// @param key 键
    template <typename KEY_T>
    void remove(KEY_T &&key)
    {
        __prefs.erase(__to_data_element(std::forward<KEY_T>(key)));
    }

    /// @brief 清空所有键值对
    void clear()
    {
        __prefs.clear(); // std::vector会自动管理内存，因此无需手动释放
    }

    /// @brief 检查指定键是否存在
    /// @tparam KEY_T 键类型
    /// @param key 键
    /// @return 是否存在
    template <typename KEY_T>
    bool contains(KEY_T &&key)
    {
        return __prefs.find(__to_data_element(std::forward<KEY_T>(key))) != __prefs.end();
    }

    /// @brief 重载[]运算符，获取指定键的值
    /// @tparam KEY_T 键类型
    /// @tparam VALUE_T 值类型
    /// @param key 键
    template <typename KEY_T, typename VALUE_T>
    VALUE_T &operator[](KEY_T &&key)
    {
        return get<VALUE_T>(std::string(""), VALUE_T());
    }
};

#endif // __PREFERENCES_H__
